/*
    io_core.c - implmentation for io communication driver 
			    This part represents the master of the system, 
				containing all global functions and other important
				stuff used by the userspace interface drivers.
	
	
	Author: Benedikt Niedermayr (2013)
	

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

	This source code is also a result of my bachelor thesis.
*/

#include "io_com.h"

#define MODULE_NAME "io_core"

struct io_com *global_pointer;
EXPORT_SYMBOL(global_pointer);

struct kiocb *iocb_kick[MAX_IOCBS]; 	// globale iocb Liste (enthält Pointer auf aktive Aufträge)
EXPORT_SYMBOL(iocb_kick);

static struct work_struct bottom_half_object;		// work object (kthreat)
struct workqueue_struct *wq;						// lokal main work queue 
struct workqueue_struct *wq_global;					// global work queue (objects get chained to this)
EXPORT_SYMBOL(wq_global);


struct work_struct gpio_bottom_half;
EXPORT_SYMBOL(gpio_bottom_half);

struct work_struct i2c_bottom_half;
EXPORT_SYMBOL(i2c_bottom_half);


/* forward declarations */
int io_send(struct io_com *iop, char *buff, int count);
int io_recv(struct io_com *iop, char *buff, int count);
int sync(struct io_com *);


static void io_core_dev_release(struct device *dev);
static const struct file_operations fops;

static struct device_driver io_core_driver = {
	.name = "io_core_driver",
	.bus = &platform_bus_type,
};


struct platform_device io_core_device = {
	.name	= "io_core_device",
	.id		= 0,
	.dev = {
		.release = io_core_dev_release,
	}
};

static DECLARE_COMPLETION(dev_obj_is_free);
static void io_core_dev_release(struct device *dev)
{
complete( &dev_obj_is_free );
}


/** io_irq_handler() - interrupt handler.
 * this handler is called for every interrupt on specified line.
 * We start a kthreat (bottom half) which does the most work within this handler
 */
irqreturn_t io_irq_handler(int irq, void *dev)
{
	/* if irq != 0 then start bottom half kthreat
	 * if irq == 0 then check (char*)dev for irq code (then irq is not called via irq subsystem! Then it's called from poll instance!)
	 */
	int irq_code;
	char *tmp;
	if(irq != 0) {
		if(queue_work( wq, &bottom_half_object) == 0)
			printk( "[%s] queue_work not successful ...\n", MODULE_NAME);
	} else {
		// Here we start the userspace specific function/kthreat directly!	
		
		//tmp  = (char *)dev;		
		//irq_code = conv_irq_code();	
	}
	
	return IRQ_HANDLED;
}



/** bottom_half_kthreat() - main bottom half kernel threat.
 * This threat is called for every interrupt and starts the userspace specific
 * kthreat via its work object. 
 *
 */
static void bottom_half_kthreat(struct work_struct *work) 
{
	int irq_code;
	/* recv irq code from io processor and start userspace specific function */
//	irq_code = recv_irq_code();
	irq_code = IRQ_CODE_GPIO1;
	// Set global_irq code!
	global_pointer->irq_code = irq_code;
	
	/* We have to ignore not yet initialised work_objects...
     * Have a look at object->func address != NULL
	 */
	switch(irq_code) {
		case (IRQ_CODE_GPIO1 | IRQ_CODE_GPIO2 | IRQ_CODE_GPIO3 | IRQ_CODE_GPIO4 | IRQ_CODE_GPIO5 | IRQ_CODE_GPIO6 |
	          IRQ_CODE_GPIO7 | IRQ_CODE_GPIO8 | IRQ_CODE_GPIO9 | IRQ_CODE_GPIO10 | IRQ_CODE_GPIO11 | IRQ_CODE_GPIO12 | 
			  IRQ_CODE_GPIO13 | IRQ_CODE_GPIO14 | IRQ_CODE_GPIO15 | IRQ_CODE_GPIO17 | IRQ_CODE_GPIO18): 

			  if(gpio_bottom_half.func != NULL){
			 	queue_work( wq_global, &gpio_bottom_half);
			 } 	
		break;
		
		case IRQ_CODE_I2C:
			 if(i2c_bottom_half.func != NULL){
			 	queue_work( wq_global, &i2c_bottom_half);
			 } 	
		break;
		case IRQ_CODE_SPI:
		break;		
		case IRQ_CODE_TIMER:
		break;
		case IRQ_CODE_CMD_ANSW:
			global_pointer->int_oc = 1;

		break;
	}


	printk("[%s] bottom half kthreat called...\n", MODULE_NAME);
}




/* sysfs attribute file for calling the sync function
 */
static ssize_t sync_func(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
	sync(global_pointer);
	printk("start_sync attribute called!\n");
	return strlen(buf)+1;
}
static DEVICE_ATTR(start_sync, 0644, NULL, sync_func);



/**
 * own_printk() - print out raw memory values with number of
 * cnt bytes.
 * @val: char pointer to array which is printed out
 * @cnt: number of bytes to be printed out
 *
 */
int own_printk(char *val, int cnt)
{
	int i;	
	char *tmp = val;
	
	for(i=0; i<cnt; i++) {
		
	
		if(*tmp == '\0') {
			printk("/0");
		} else {
			printk("%c", *tmp);	
		}

		//if(i == (cnt-1))
			//printk("\n");

		tmp++;
	}
	printk("\n");
	return 0;
}



/**
 * new_char() - Get new pointer of char
 * with specified memory. 
 * @num: number of bytes to be reserved
 * 
 */
char *new_char(int num){

	char *t;
	t = kmalloc(num,GFP_KERNEL);
	memset(t, 0, num);
	return t;
}
EXPORT_SYMBOL(new_char);



/**
 * create_params_string() - This function creates the complete 
 * parameter string composed of the strings of each parameter.
 * @p: pointer to cmd struct containing all neccessary information
 */
int create_params_string(struct cmd *p)
{
	int i = 1;	
	int string_len, offset;
	struct params *cur_element;
	struct list_head *pos, *prev;

	/* Allocate memory for complete parameter string */
	p->params_string = new_char(MAX_DATA_LEN);

	/* Create complete params_string */
	string_len = 0;
	offset = 0;

	list_for_each_prev(pos, &p->root.list){
		cur_element = list_entry(pos, struct params, list);
		
		if(!offset){ // first Parameter
			string_len = cur_element->len_const + cur_element->len_val;
			memcpy(&p->params_string[offset], cur_element->string, string_len);
			offset += string_len;
			i--;
		} else{ // following parameters	
			string_len = cur_element->len_const + cur_element->len_val;
			memcpy(&p->params_string[offset], cur_element->string, string_len);
			offset += string_len;
		}
	}	
	p->params_string_len = offset;		

	/* delete params list */
	list_for_each_safe(pos, prev, &p->root.list){
		cur_element = list_entry(pos, struct params, list);
		list_del(pos);
		kfree(pos);
	}

	return 0;
}
EXPORT_SYMBOL(create_params_string);






/**   
 * add_param_to_list() - Does exactly what it says.
 * This function should be called for initializing
 * each parameter and adding it to the parameter
 * list 
 * @nr:	Number of parameter (e.g. for I²C there are 2 parameters)
 *		1: Slave address
 *		2: payload data
 * @val: parameter value
 * @p:   pointer to cmd struct containing all neccessary information
 */
int add_param_to_list(int nr, char *val, struct cmd *p, int len)  
{
	//int i;	
	//struct list_head *pos;
	struct params *new_par;

	/* Create a new parameter list element */
	new_par = kmalloc(sizeof(*new_par), GFP_KERNEL);
	if (new_par == NULL)
		return -ENOMEM;
	
	/* Initialize length, payload and nummer of parameter */
	new_par->len_val = len; 						 
	new_par->val = new_char(len);
	memcpy(new_par->val, val, new_par->len_val);  
	new_par->nr = nr;

	/* create param string of this new list element
     * 
	 * => P{nr}:{length}:{val}
     */

	/* Allocate buffer for parameter string (and some more) */
	new_par->string = new_char(new_par->len_val + 10);
	sprintf(new_par->string, "P%d:%d:", new_par->nr, new_par->len_val);
	new_par->len_const = strlen(new_par->string);

	/* Now copy parameter data */ 
	memcpy(&new_par->string[new_par->len_const], val, new_par->len_val ); 
	
	if(DEBUG == 1)
		printk("String of Parameter %d created\n", new_par->nr);
	

	list_add(&new_par->list, &p->root.list);
	return 0;
}
EXPORT_SYMBOL(add_param_to_list);





/**
 * create_raw_package() - This does create a package with
 * raw user data. This means the data from userspace is directly
 * interpreted as cmd_string! It will only be called in raw data interface driver.
 */
int create_raw_package( int id, struct cmd *p, char *user_string, int user_string_len)
{

	// USERSTRING -> {Pack_FLAG:1}{Interface:1}{direction:1}{:XX: 2}{P1:xxxxx}......
	// We only have to fill cmd_id with id.
	char *tmp_string = user_string;  
	char c[3];

	sprintf(&c[0], "%d", id);
	
	// Get to tmp_string[3] position
	tmp_string++; tmp_string++; tmp_string++;
	*tmp_string = c[0]; //first ID character
	*tmp_string = c[1]; //second ID character
	if(DEBUG == 1)
		printk("raw user command => %s", user_string);
	return 0;
	
}

/**
 * create_package() - This function creates a full cmd_string
 * containing the whole data, required for function commands
 * to the i/o controller.
 * @cmd_id: Make difference between request and helps assining answers   
 * @interface: Used userspace interface
 * @direction: this character doesn't matters; I could be helpfull later.  
 * @p: pointer to cmd struct containing all neccessary information
 * @p_flag: sepcifies a function (0x00) or a system package(0x01)
 * @cmd_flag: cmd_flag, specific for a sys or func command
 */
int create_package(int cmd_id, char interface, char direction, struct cmd *p, int p_flag, char cmd_flag)
{
	int offset;		

	/* allocate memory for cmd_string */
	p->cmd_string = new_char(MAX_DATA_LEN);


	/* initialize elements */
	p->cmd_id = cmd_id;
	p->interface = interface; 	
	p->direction = direction;
	p->cmd_flag = cmd_flag;
	p->corresp = NULL;
	

	/* join together all initialized elements to a string (cmd_string) 
	 * => {cmd_flag}{interface}{direction}{cmd_id}{parameter string}
	 *
	 * => {cmd} == {interface}{direction}
     */
	offset = 0;
	if(DEBUG == 1)
		printk("Creating cmd_string...\n");

	if(cmd_id <= 9) {

		sprintf(p->cmd_string, "%c%c%c0%d", p->cmd_flag, p->interface, p->direction, p->cmd_id);
		offset = strlen(p->cmd_string);
		memcpy(&p->cmd_string[offset], p->params_string, p->params_string_len);			
	} else{

		sprintf(p->cmd_string, "%c%c%c%d", p->cmd_flag, p->interface, p->direction, p->cmd_id);
		offset = strlen(p->cmd_string);
		memcpy(&p->cmd_string[offset], p->params_string, p->params_string_len);
	}
	p->cmd_len = offset + p->params_string_len; /* NEW_CMD Position! */

	/* Add the NEW_CMD character at the end of each command */
	p->cmd_string[p->cmd_len] = NEW_CMD;
	
	if(DEBUG == 1)
		printk("Created cmd_string...\n");

		
	return 0;
}

/**
 * create_func_package() - This function creates a function package.
 * Function packages are used for transmit data over io processor
 * interfaces.
 * @cmd_id: Make difference between request and helps assining answers   
 * @interface: Used userspace interface
 * @direction: indicates read or write access
 * @p: pointer to cmd struct containing all neccessary information
 */
int create_func_package (int cmd_id, char interface, char direction, struct cmd *p)
{
		return create_package(cmd_id, interface, direction, p, 0x00, FFUNC);
}
EXPORT_SYMBOL(create_func_package);

/**
 * create_sys_package() - This function creates system package. 
 * System packages are used to set a state of the io processor.
 * Also the state of the io controller interfaces can be set.
 * @iop: pointer to io_com struct containig all global information
 * @cmd_id: Make difference between request and helps assining answers
 * @interface: Specifies the current Interface driver, from which this function is called.    
 * @sys_cmd: Value for system command
 */
int create_sys_package (int cmd_id, char *sys_cmd, struct cmd *p)
{
	char tmp[3];
	char *c = sys_cmd;
	tmp[0] = *c++;
	tmp[1] = *c++; 

	return create_package(cmd_id, tmp[0], tmp[1], p, 0x01, FSYS);
}
EXPORT_SYMBOL(create_sys_package);





/**
 * add_cmd_to_list() - Add the cmd element to the global command list.
 * Make also some checks in order to get shure that the cmd element
 * is initialized correctly.
 * @iop: pointer to io_com struct containig all global information
 * @p:	 pointer to cmd struct containing all neccessary information
 */
int add_cmd_to_list(struct cmd *pm, struct io_com *iop)
{
	
	struct list_head *pos;
	struct cmd *cur_el;

mutex_lock(&iop->add_cmd_lock);
	printk("Adding cmd to list:\n");
	if(DEBUG == 1)	
		printk("###########################################\n");
	
	if(iop != NULL)
		list_add(&pm->list, &iop->cmd_root.list);

	if(DEBUG == 1) {	
		/* check the global cmd list */
		list_for_each_prev(pos, &iop->cmd_root.list){
		
			cur_el = list_entry(pos, struct cmd, list);

			printk("cmd_id= %d\n", cur_el->cmd_id);
			printk("interface= %c\n", cur_el->interface);
			printk("direction= %c\n", cur_el->direction);
			printk("cmd_flag= %c\n", cur_el->cmd_flag);
			printk("cmd_len= %d\n", cur_el->cmd_len);
			printk("cmd_string=");
			own_printk(cur_el->cmd_string, cur_el->cmd_len);
			printk("###########################################\n");		
			
		}
	}
	if(DEBUG == 1){
		printk("Added cmd to list\n");
		printk("\n");
	}
mutex_unlock(&iop->add_cmd_lock);
	return 0;
}
EXPORT_SYMBOL(add_cmd_to_list);




/**
 * convert_recvbuff_to_list() - Converts the receive buffer and
 * splitts it into it's single answer packages. Usually only answer
 * packages get received. But irq packages are also possible.
 * Therefore we check the first Flag(IRQ or Answer)!
 * @iop: pointer to io_com struct containig all global information
 */

int convert_recvbuff_to_list(struct io_com *iop)
{
		
	/*
	 * Answer package string =>  A XX YY a:lenx:payloadx
     */


	char *answ_pos, *tmp;
	char id_char[3];
	char len_char[10];
	int i,k;
	bool eof=false;
	struct answ_cmd *new_answ, *cur_element;
	struct list_head *pos;
	
	if(DEBUG == 1) {
		printk("\n\n");
		printk("Creating answer list\n");
	}

	answ_pos = &iop->debug_answer_test_string[0];


	while(eof == false) {
		
		/* Create a new answ_cmd list element */
		new_answ = kmalloc(sizeof(*new_answ), GFP_KERNEL);
		if (new_answ == NULL)
			return -ENOMEM;


		/* check for package flag */ 	
		if (*answ_pos == FANSW ) {
			/* answer package */
			//printk("AF_Character =>%c<=\n", *answ_pos);		
			new_answ->cmd_flag = *answ_pos;
			answ_pos++;
			
			/*Now on pos interface */ 
			//check_and_get(); --> check also the content for validity
			//printk("Interface_Character =>%c<=\n", *answ_pos);
	
			new_answ->interface = *answ_pos;
			answ_pos++;

			/* Now on pos direction */
			//printk("Dir_Character =>%c<=\n", *answ_pos);
			new_answ->direction = *answ_pos;
			answ_pos++;


			/* Now on pos id */	
			//printk("ID_Character =>%c<=\n", *answ_pos);		
			id_char[0] = *answ_pos;
			answ_pos++;
			//printk("ID_Character =>%c<=\n", *answ_pos);
			id_char[1] = *answ_pos;
			id_char[2] = '\0';

			new_answ->cmd_id = -1;
			sscanf((const char *)&id_char[0],"%d", &new_answ->cmd_id);

			if(new_answ->cmd_id == -1) {
				printk("Error while getting cmd_id!\n");
				return -1;	
			}

			answ_pos++;
			
			/* Now on pos A character */
			//printk("A_Character =>%c<=\n", *answ_pos);
			if(*answ_pos != 'a') {
				printk("Something was wrong! We are not on pos of A character!\n");
				printk("Pos contains character =>%c<=\n", *(answ_pos));
				return -1;		
			}	
			answ_pos++;
	
			/* Now on pos ':' character */
			//printk(":_Character =>%c<=\n", *answ_pos);
			if(*answ_pos != ':') {
				printk("Something was wrong! We are not on pos of : character!\n");
				printk("Pos contains character =>%c<=\n", *(answ_pos));
				return -1;		
			}	
			answ_pos++;

			/* Now on pos length */	
			//printk("Len_Character =>%c<=\n", *answ_pos);		
			i = 0;
			while(*answ_pos != ':') {
						
				len_char[i] = *(answ_pos);
				i++;
				answ_pos++;			
			}
			len_char[i] = '\0';
			new_answ->answ_len = -1;
			sscanf((const char *)&len_char[0],"%d", &new_answ->answ_len);
			
			if(new_answ->answ_len == -1) {
				printk("Error while getting answ_len!\n");
				return -1;	
			}
			answ_pos++;
			//printk("Answ_len = %d\n", new_answ->answ_len);

			k = new_answ->answ_len;
			/* Now at payload position */
			new_answ->answer_payload = new_char(new_answ->answ_len);
			i = 0;
			tmp = new_answ->answer_payload;
			//printk("Answ_len = %d\n", new_answ->answ_len);
			while(i < k) {
				printk("Payload_Character =>%c<=\n", *answ_pos);
				*(tmp++) = *(answ_pos++);
				i++;
			}
		
			
			
			/* Now at pos FANSW or at pos NEW_CMD */
			if(*answ_pos == NEW_CMD) {
				answ_pos++;			
			} else if (*answ_pos == END_OF_FRAME) {
				eof=true;
			} else {
				printk("Error while getting NEW_CMD or END_OF_FRAME character!\n");	
				printk("pos contains character =>%c<=\n",*answ_pos);		
			}
	
			/* add new answer to list */
			list_add(&new_answ->list, &iop->answ_root.list);


			/* delete recv_buff !! 
			 * => free(iop->def_buff_recv);
			 */
						

		} else {
			return -1;	
		}
	}

	if(DEBUG == 1) {
	/* ALL ELEMENTS CREATED. Lets have a look.... */
		printk("All list elements created...Let's have a look.\n");
		list_for_each_prev(pos, &iop->answ_root.list) {
		
			cur_element = list_entry(pos, struct answ_cmd, list);
	
			printk("cmd_id=>%d\n", cur_element->cmd_id);
			printk("answ_len=%d\n", cur_element->answ_len);
			printk("interface=%c\n", cur_element->interface);
			printk("direction=%c\n", cur_element->direction);
			printk("cmd_flag=%c\n", cur_element->cmd_flag);	
			printk("answer_payload=%s\n", cur_element->answer_payload);	
			
		}
	}

	return 0;
}
EXPORT_SYMBOL(convert_recvbuff_to_list);


/**
 * alloc_requ_and_answ() - Allocating algorithm.
 * Allocates each request to its specific answer element. 
 * @iop: pointer to io_com struct containig all global information
 */
int alloc_requ_and_answ(struct io_com *iop)
{
	
	struct list_head *pos1,*pos2;
	struct cmd *cur_cmd_el;
	struct answ_cmd *cur_answ_el;
	int i,o;

	i=0;
	o=0;
	
	printk("\n\n");
	printk("ALLOCATING ALGORITHM\n");
	
	/* O-List iteration */
	list_for_each_prev(pos1, &iop->cmd_root.list) {
		cur_cmd_el = list_entry(pos1, struct cmd, list);
		o++;

		/* is corresp pointer already allocated ?! */
		//printk("corresp_addr=%p\n", cur_cmd_el->corresp);
		if(cur_cmd_el->corresp != NULL) {
			printk("Command element alreay allocated!\n");
			continue;
		}

		/* I-List iteration */
		list_for_each_prev(pos2, &iop->answ_root.list) {
			cur_answ_el = list_entry(pos2, struct answ_cmd, list);
			i++;

			/* command_id matches */
			//printk("cur_cmd_el->cmd_id=%d\n", cur_cmd_el->cmd_id);
			//printk("cur_answ_el->cmd_id=%d\n", cur_answ_el->cmd_id);
			if(cur_cmd_el->cmd_id != cur_answ_el->cmd_id)
				continue;
			//printk("cmd_id match!\n");
							
			/* interface element also matches */
			//printk("cur_cmd_el->interface=%c\n", cur_cmd_el->interface);
			//printk("cur_answ_el->interface=%c\n", cur_answ_el->interface);
			if(cur_cmd_el->interface != cur_answ_el->interface)
				continue;			
			printk("interface match!\n");			

			/* if direction also matches, we have an allocated element */ 
 			if(cur_cmd_el->direction == cur_answ_el->direction) {
				//printk("Complete match found! (i_el=%d, o_el=%d)\n", i, o);
				//printk("Matched cmd_id=%d\n",cur_answ_el->cmd_id);
				//printk("Matched interface=%c\n",cur_answ_el->interface);
				//printk("Matched direction=%c\n",cur_answ_el->direction);				
				//printk("Creating matched entry with cmd->corresp\n");
				cur_cmd_el->corresp = cur_answ_el;
				break;							
			}
		
			
		}
	}

	printk("END OF ALLOCATION ALGORITHM\n");
	return 0;

}
EXPORT_SYMBOL(alloc_requ_and_answ);




/**
 * create_send_buff() - This function joins together all single 
 * cmd_strings to an ready to send send_buffer string. The handshake
 * request string is also created!
 * @iop: pointer to io_com struct containig all global information
 */
int create_send_buff(struct io_com *iop)
{
	struct list_head *pos;
	struct cmd *cur_element;	
	int offset, len, len_hand_string;
	char tmp[30];


	/* First of all calculate the length of complete sendbuff! */
	len = 0;
	list_for_each_prev(pos, &iop->cmd_root.list) {
		cur_element = list_entry(pos, struct cmd, list);
		len += cur_element->cmd_len + 1;  // we need +1 because of NEW_CMD character
	}
		len++; //+1 because of END_OF_FRAME character! 

	/* if send buffer length = 0, then we have no elements! */
	if(len == 0)
		return -EIO;

	if(DEBUG == 1)
		printk("LENGTH SEND BUFFER=%d\n", len);

	iop->send_buff_len = len;		
	iop->def_buff_send = new_char(len); 

	/* cmd Liste durchgehen und p->send_buff per memcpy mit cmd_string elementen füllen
     * die länge jedes cmd_strings element (inklusive NEW_CMD Zeichen) ist ebenfalls
     * mit angegeben!!!!!
	 */
	offset = 0;
	list_for_each_prev(pos, &iop->cmd_root.list) {
		cur_element = list_entry(pos, struct cmd, list);
		memcpy(&iop->def_buff_send[offset], cur_element->cmd_string, cur_element->cmd_len);
		offset += cur_element->cmd_len;
		iop->def_buff_send[offset] = NEW_CMD;
		offset++;
	}

	/* add END_OF_FRAME character */	
	iop->def_buff_send[offset] = END_OF_FRAME;
	
	if(DEBUG == 1) { 
		printk("SEND BUFFER =>");
		own_printk(iop->def_buff_send, len);
	}


	/* iop->handhshake_request string aufbauen
     *  ==>   "AA:len:"
  	 */
	sprintf(&tmp[0], "%d", len);
	len_hand_string = strlen(tmp);
	iop->handshake_request_string = new_char(4 + len_hand_string);
	sprintf(iop->handshake_request_string, "AA:%d:", len);
	return 0;


}
EXPORT_SYMBOL(create_send_buff);






/**
 ** DEBUG FUNKTION   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 ** Erstellt einen Dummy Antwortstring (als würde dieser vom io controller kommen)
 **/
void create_debug_answer_string(struct io_com *iop)
{	
	/*
	 * Answer package string =>  A XX YY A:lenx:payloadx    (xx=COMMAND(Interface+Direction),  yy=ID)
     */
	struct list_head *pos;
	struct cmd *cur_element;
	char *part;
	
	int offset = 0;

	list_for_each_prev(pos, &iop->cmd_root.list) {
		
		part = new_char(1024);		
		cur_element = list_entry(pos, struct cmd, list);
		
		
		//Zuerst das Antwort Stück erstellen in temporäre Variable 
		if(cur_element->cmd_id < 10){		
			sprintf(part, "A%c%c0%da:%d:CABDEFGHIKx", cur_element->interface, cur_element->direction, cur_element->cmd_id, 10);
		} else {
			sprintf(part, "A%c%c%da:%d:CABDEFGHIKx", cur_element->interface, cur_element->direction, cur_element->cmd_id, 10);
		}
		memcpy(&iop->debug_answer_test_string[offset], part, strlen(part));

		offset += strlen(part);
		kfree(part);			
		iop->debug_answer_test_string[offset] = END_OF_FRAME;
						
		
		//debug_answer_test_string		
	}
	printk("debug_answer_test=>%s<=\n", iop->debug_answer_test_string);
}
/************************************************************************************************************************************/
/**********************************************END DEBUG FUNTTION********************************************************************/
/************************************************************************************************************************************/
/************************************************************************************************************************************/
/************************************************************************************************************************************/


/**
 * handshake_master() - Initiate a handshake with the
 * io processor in master mode.
 * @handshake_buff: buffer containing information
 * needed for handshaking the slave.
 *
 * Returns 0, if handshake was OK, the Master can now send
 * the complete send_buff!
 * Else an error number created by the slave gets returned!
 */
int handshake_master(char *handshake_buff)
{
	/* Ablauf
     * 	1. Senden des erstellten Handshake Strings (AA:len:\n)
	 *	2. Slave löst irq aus (KEIN Empfangen des IRQ Codes, da Master ja weis warum irq ausgelöst wurde)
	 *  3. Slave antwortet mit AA wenn alles OK ist.			 ====> RETURN 0
	 *  3b. Slave antwortet mit 00 wenn etwas nicht OK ist!!!    ====> RETURN ERROR_NUM
	 */ 
	return 0;
}
//EXPORT_SYMBOL(handshake_master);

/**
 * handshake_slave() - Initiate a handshake with the
 * io processorin slave mode.
 * @handshake_buff: buffer containing information
 * needed for handshaking the slave.
 *
 * Returns number of following bytes, if handshake was OK, the Slave can now send
 * the complete recv_buff!
 * Else an error number created by the slave gets returned!
 */
int handshake_slave(void)
{
	/* Ablauf
	 * 1. Slave löst spontan einen IRQ aus (Dies passiert schon innerhalb sync(), also auserhal von handshake_slave()) 
	 * 2. Master empfängt von Slave IRQ_CODE_CMD_ANSW. (Geschieht automatisch im bottom_half_handler)
	 * 3. Nun sendet Master AA zur Bestätigung des Interrupts
     * 4. Nun empfängt Master von Slave 4 Bytes(inklusive EOF Delimitierer), welche auf die Länge des Antwortstrings hinweisen.
	 * 5. RETURN Länge des antwort Buffers wenn genügend Speicher frei
 	 * 5b. RETURN ERROR_NUM
	 */
   
	
	return 0;
}
//EXPORT_SYMBOL(handshake_slave);





/**
 * kick_iocbs() - Starts all active iocb jobs!
 * 
 */
int kick_iocbs(void)
{
	int i;
	printk("Starting kick_iocbs...\n");
	mutex_lock(&global_pointer->iocb_lock);

	if(global_pointer->iocb_cnt == 0) {
		printk("No active iocb avaiable!\n");
		goto unlock;	
	} else {
		/* now start kicker interface... kick all available jobs */
		for(i=0; i<global_pointer->iocb_cnt; i++) {
			printk("iocb_kick element[%d], address=%p\n", i, iocb_kick[i]);
			
			kick_iocb(iocb_kick[i]); 

			/* Hier muss evtl. noch eine Synchronisation mit der retry-Funktion stattfinden,
			 * da diese als kthreat parallel hierzu abläuft! wake_up Funktion
			 * -> Dann alle iocb_kick Elemente auf NULL setzten! */
			
		}
	}
	global_pointer->iocb_cnt = 0;
	
	mutex_unlock(&global_pointer->iocb_lock);	
	return 0;

unlock:
	mutex_unlock(&global_pointer->iocb_lock);
	return -EIO;
}



/**
 * sync() - Synchronize all send and receive Data.
 * Do also forward data to Userspace instance!
 * @iop: pointer to io_com struct containig all global information 
 */
int sync(struct io_com *iop)
{
	int ret;
	//int answ_len;
	/* 
	 * Starte Transfer 
     * 1. Baue aus aktueller Anfrage Liste den sende_buffer 			=>create_send_buff	
     * 1b. Master HANDSHAKE
	 * 2. Sende_buffer Transfer 										=>io_send_cmd_buff
	 * 3. Warte auf IRQ bzw. Antwort vom I/O controller					=>completion_wait
	 * 3b. Slave HANDSHAKE
     * 4. Empfange Antwort Buffer 										=>io_recv_cmd_buff
     * 5. Erweitere Antwort Liste mit recv_buff elementen 				=>convert_recvbuff_to_list
	 * 6. Führe Zuordnung zwischen Anfrage und Antwort Elementen durch! =>alloc_requ_and_answ 
     */	

	//func() is called only once at same time!
	mutex_lock(&iop->sync_func_lock);  
	
	/* build send buffer...
     * We need to lock this critical part
	 * because of access to global cmd list.
     * If we start this function then another process
	 * may first add it's cmd to list. Or the other
     * process has to wait for next sync() call.
	 */
	mutex_lock(&iop->add_cmd_lock);
	ret = create_send_buff(iop);
	mutex_unlock(&iop->add_cmd_lock);
	if(ret)
		goto unlock;

	if(SIMULATE != 1) {
		if((ret = handshake_master(iop->handshake_request_string)) != 0) {
			printk("Master Handshake not accepted! Error code is %d\n", ret);
			goto unlock;   
		}
	}	

	/* Send buffer is ready to send
     * so let's send it
     */
	ret = io_core_send(iop, iop->def_buff_send, iop->send_buff_len);
	if(ret)
		goto free;
	
	// release send buffer
	kfree(iop->def_buff_send);
	
	if(SIMULATE != 1) {
	
		/* wait for IRQ(recv_buffer_IRQ)
  	     * As i2c or spi driver we can simple
    	 * wait for an irq(make this function sleep and wake it up in the irq handler). 
   	     * On USB we have to poll the io processor after a given time window
     	 */
		while(iop->int_oc == 0) {} //This could could result in a race condition, but it's easy to implement :)
		iop->int_oc = 0; 		   //Reset interrupt occured flag

	
		// Now it's time for slave handshake
		if((ret = handshake_slave()) < 0)
		{
			printk("Slave Handshake not accepted! Error code is %d\n", ret);
			goto unlock;
		}	  


		/* allocate memory for recv_buff dependend on ret-value 
		 * of slave handshake
	     */
		iop->def_buff_recv = new_char(ret);


		ret = io_core_recv(iop, iop->def_buff_recv, iop->recv_buff_len);
		if(ret) {
			goto free;
		}
	
	} else {
	
		/** ONLY START DEBUG FUNCTION **/
		create_debug_answer_string(iop);
	}

	/* Now create answ_list */
	convert_recvbuff_to_list(iop);

	/* do allocating between requests and answers */
	alloc_requ_and_answ(iop); 

	/* Start all active asyncronous waiting userspace instances */
	kick_iocbs();

	mutex_unlock(&iop->sync_func_lock);
	return 0;


free:
	kfree(iop->def_buff_send);
unlock:
	mutex_unlock(&iop->sync_func_lock);
	return -EIO;
}
EXPORT_SYMBOL(sync);


/**
 * send_cmd_buff - Send a command to io_extension 
 * @iop:	global io system data
 * @buff: buffer to be sent
 * @count: length of buffer 
 * Returns negative errno, or else 0.
 */
int io_core_send(struct io_com *iop, char *buf, int count)
{

	/* lock this critical access to global element */
	mutex_lock(&iop->async_lock);

	if(global_pointer->io_handler_send(iop, buf, count) < 0)
		goto err;
	
	mutex_unlock(&iop->async_lock);
	return 0;

err:
	mutex_unlock(&iop->async_lock);
	return -EIO;
}
EXPORT_SYMBOL(io_core_send);



/**
 * io_recv - receive data from connected io processor
 * @iop:	global io system data
 * Returns negative errno, or else 0.
 */
int io_core_recv(struct io_com *iop, char *buf, int count)
{

	/* lock this critical access to global element */
	mutex_lock(&iop->async_lock);

	if(global_pointer->io_handler_recv(iop, buf, count) < 0)
		goto err;
	
	/* unlock this critical part*/
	mutex_unlock(&iop->async_lock);

	return 0;

err:
	mutex_unlock(&iop->async_lock);
	return -EIO;
}
EXPORT_SYMBOL(io_core_recv);



/***************************************************************************/
/***************************************************************************/
/****************************************************************************/


static int __init io_core_init(void)
{	
	int ret;
	struct io_com *iop;

	/* initialize io_com structure */
	iop = kmalloc(sizeof(*iop), GFP_KERNEL); 
	if(iop == NULL) {	
		printk("Error while allocate memory\n");	
		return -ENOMEM;
	}	
	
	iop->io_core_number = MKDEV(MAJOR_IO_CORE,0);
	if(register_chrdev(MAJOR_IO_CORE, "io_core_dev", &fops) == 0) {
		/* register driver and it's platform device */
		ret = driver_register(&io_core_driver);	
		platform_device_register(&io_core_device);
		iop->io_core_dev = &io_core_device.dev;
		/* We don't need to use device_bind_driver(), driver-device binding will happen
	     * automatically!!
		 */
	} else {
		goto free_data;	
	}

	/* set global pointer to io_com structure
	 * Now we get access to this structure from
     * everywhere
     */
	global_pointer = iop;

	/* Init mutex for critical parts */
	mutex_init(&iop->async_lock);
    mutex_init(&iop->cnt_lock);
	mutex_init(&iop->sync_func_lock);
    mutex_init(&iop->add_cmd_lock);
	mutex_init(&iop->iocb_lock);

	/* Set counter for asynchrounus orders */
	iop->iocb_cnt = 0;

	/* register a new class (io_extension) */
	iop->io_class = class_create(THIS_MODULE, "io_com");
	if( IS_ERR(iop->io_class) ) {
		pr_err(	"Error while creating class\n");
		//Avoid memory leak
		kfree(iop);
		return -EIO;
	}

	/* Now support the Udev/Mdev functionality of
     * automatic creating dev-files. This will add an additional device
	 */
	iop->io_core_user_dev = device_create(iop->io_class, NULL, iop->io_core_number ,NULL, "io_core_dev");	

	/* initialize the global cmd- and answer list */
	INIT_LIST_HEAD(&iop->cmd_root.list);
	INIT_LIST_HEAD(&iop->answ_root.list);

	/* We put the device file to io_core_dev (/sys/class/io_com_/io_core_dev/start_sync) */
	ret = device_create_file(iop->io_core_user_dev, &dev_attr_start_sync);	
	if(ret)
		return ret;

	/* initialize the work_queue for bottom half kthreat.
     */
	INIT_WORK(&bottom_half_object, &bottom_half_kthreat);
	wq = create_workqueue("io_core w_queue");
	wq_global = create_workqueue("io_core global_queue");	
		

	/* register interrupt, but only if irq line is connected.
	 * If no interrupt is registered, we will activate irq poll threat
     */
	if(IRQ_LINE == IRQ_LINE_CON) {
		if(request_irq (gpio_to_irq(IO_IRQ_GPIO), io_irq_handler, IO_IRQ_TRIGGER, "io_processor interrupt",(void *)iop)) {
        		printk (KERN_ERR "request_irq() returned an error\n");
			return -EIO;
		}
	} else if (IRQ_LINE == IRQ_LINE_DISCON){
		////// CREATE POLL THREAT ///////////////
		/////////////////////////////////////////
		/////////////////////////////////////////
	}

	/* initalize interrupt ocurred flag */
	iop->int_oc = 0;

	printk("[io_core] driver loaded.\n");
	return 0;

free_dev_attr:
	device_remove_file(&io_core_device.dev, &dev_attr_start_sync );
	if(wq) {destroy_workqueue(wq);}
	device_destroy(global_pointer->io_class, global_pointer->io_core_number);
free_data:
	kfree(iop);
	return -EIO;
}



static void __exit io_core_exit(void)
{
	struct io_com *iop;		
	
	if(global_pointer == NULL)
		return;
	iop = global_pointer;

	free_irq(gpio_to_irq(IO_IRQ_GPIO),(void *)iop);
	if(wq)
		destroy_workqueue(wq);

	device_remove_file(&io_core_device.dev, &dev_attr_start_sync );
	device_destroy(iop->io_class, global_pointer->io_core_number);
	class_destroy(iop->io_class);

	platform_device_unregister( &io_core_device );
	driver_unregister(&io_core_driver);
	unregister_chrdev(MAJOR_IO_CORE, "io_core_dev");
	kfree(global_pointer);	
		
}

module_init( io_core_init );
module_exit( io_core_exit );

MODULE_AUTHOR("Benedikt Niedermayr");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("i/o controller core-driver");
MODULE_SUPPORTED_DEVICE("none");

